home *** CD-ROM | disk | FTP | other *** search
/ Mac Magazin/MacEasy 32 / Mac Magazin and MacEasy Magazine CD - Issue 32.iso / Grafik & Text / OzTeX3.0 / BibTeX / bibEngine.tcl next >
Text File  |  1997-02-12  |  19KB  |  608 lines

  1. ## -*-Tcl-*-
  2.  # ###################################################################
  3.  #    BibTeX for MacOS -- scripts for GURL interaction with Alpha.
  4.  # 
  5.  #    FILE: "bibEngine.tcl"
  6.  #                                      created: 13/11/96    {1:05:50 am} 
  7.  #                                  last update: 12/2/97 {12:41:23 pm} 
  8.  #    Author:    Vince Darley
  9.  #    E-mail:    <darley@fas.harvard.edu>
  10.  #      mail:    Division of    Applied    Sciences, Harvard University
  11.  #            Oxford Street, Cambridge MA    02138, USA
  12.  #       www:    <http://www.fas.harvard.edu/~darley/>
  13.  #    
  14.  #    INSTALLATION PROCEDURE:
  15.  #    
  16.  #    Add    the following line to your "prefs.tcl" (a file located in Alpha's      
  17.  #  preferences folder inside your Preferences folder in your System folder):
  18.  #  
  19.  #      eventHandler GURL GURL GURLHandler
  20.  #  
  21.  #  This declares an event handler so we receive GURL events from
  22.  #  the BibTeX application (Note: do not copy the '#' at the beginning of
  23.  #  the line).  Now open Internet Config, select 'helpers' and 'add' a 
  24.  #  helper for 'bibresult', and select as helper the application 'Alpha'. 
  25.  # 
  26.  #  Then move this file to the 'UserCode' folder inside the 'Tcl' folder
  27.  #  which is located in the same place as the application Alpha.  Now
  28.  #  open Alpha, hit 'cmd-Y', and select 'Rebuild Tcl Indices' from the
  29.  #  menu.  After a minute or so, you can quit Alpha, and installation is
  30.  #  complete.  If the old file 'BibTeXAlphaScripts.tcl' exists, delete it.
  31.  # 
  32.  #  The only further choice you have is the value of the variable
  33.  #  Bib_AutoIndex, which you can set below.
  34.  # 
  35.  #  (For the technically minded: I use Internet Config to do the dirty work
  36.  #  of sending apple-events for me.  One day I'll write my own code, but this
  37.  #  hack works quite well for the moment.)
  38.  #  
  39.  #  modified by  rev reason
  40.  #  -------- --- --- -----------
  41.  #  13/11/96 VMD 1.0 original -- for use with BibTeX 1.1.4
  42.  #  22/11/96 VMD 1.1 various improvements plus a name change
  43.  #  31/1/97  VMD 1.2 handles some warnings and .bst files better now
  44.  #  6/2/97   VMD 1.3 added some features, handles some more obscure errors 
  45.  # ###################################################################
  46.  ##
  47.  
  48.  
  49. # 0=never make index (except manually)
  50. # 1=ask user when necessary 
  51. # 2=always remake when necessary
  52. # NOTE: set this to _your_ preference out of the above.
  53. set Bib_AutoIndex 1
  54.  
  55. # Used by bibPickBibliography to set a default in the listpick dialog
  56. # It's useful because you will often want to add a bunch of new items
  57. # in a row to the same bibliography.
  58. # NOTE: this is set by my code, not you.
  59. set Bib_defaultBib ""
  60.  
  61. ## 
  62.  # -------------------------------------------------------------------------
  63.  #     
  64.  # "GURLHandler" --
  65.  #    
  66.  #    Handle general GURL    events by extracting the type 'ftp', 'http',…
  67.  #    and    calling    a procedure    ${type}GURLHandler with    a single parameter
  68.  #    which is the extracted resource.  Can be put to more general use.
  69.  # -------------------------------------------------------------------------
  70.  ##
  71. proc GURLHandler {msg} {
  72.     if ![regsub {.*“(.*)”.*} $msg {\1} gurl] {
  73.         alertnote "Didn't understand GURL: $msg"
  74.         return
  75.     }
  76.     set GURLtype [lindex [split $gurl ":"] 0]
  77.     set GURLvalue [string range $gurl [expr 1+[string length $GURLtype]] end]
  78.     if [catch {${GURLtype}GURLHandler $GURLvalue} msg] {
  79.         message $msg
  80.     }
  81. }
  82.  
  83. ## 
  84.  # -------------------------------------------------------------------------
  85.  #     
  86.  # "bibresultGURLHandler" --
  87.  #    
  88.  #    Handle 'bibresult' GURLs, as sent by the application BibTeX.  These
  89.  #    goto bibliography files, errors, warnings etc.    We do the parsing here.
  90.  #    See    BibTeX's readme    file for the syntax    of the message.
  91.  # -------------------------------------------------------------------------
  92.  ##
  93. proc bibresultGURLHandler {msg} {
  94.     # Extract base .aux file name (full path description or 'Unknown')
  95.     set bpos [string first ".aux:" $msg]
  96.     set base_aux [string range $msg 0 [incr bpos 3]]
  97.     # Get rest of message
  98.     set msg [string range $msg [incr bpos 2] end]
  99.     # if it's a file name; we need to open it:
  100.     if [regsub {.*: ([^.]+.(aux|bst|bib))([ \t].*)?} $msg {\1} filename] {
  101.         set rest [string range $msg [expr [string first $filename $msg] + [string length $filename] ] end]
  102.         bib_OpenFile ${filename} [file dirname $base_aux]
  103.         if {[string trim $rest] == "not found"} {
  104.             alertnote "This file was not found by BibTeX.  You should either move it to another location, or add to BibTeX's search paths."
  105.         }
  106.         return
  107.     }
  108.     
  109.     switch [lindex [split $msg "-"] 0] {
  110.       "Warning" {
  111.           # extract warning type and find the entry
  112.           # the last item is the entry (minus quotes possibly)
  113.           set realmsg [set msg [string range $msg 9 end]]
  114.           if {[string first ";" $msg] != -1} {
  115.               # we have some stuff _after_ the item
  116.               set msg [lindex [split $msg ";"] 0]
  117.           } 
  118.           # the msg ends in the bib entry
  119.           set llen [llength $msg]
  120.           set item [string trim [lindex $msg [incr llen -1]] {"}]
  121.           set warning [lrange $msg 0 [incr llen -1]]
  122.           if { $warning == "I didn't find a database entry for" } {
  123.               # no entry exists, prompt to make one
  124.               bib_NoEntryExists $item $base_aux
  125.               return
  126.           } else {
  127.               # go to a current entry
  128.               bibGotoEntry $item
  129.               beep
  130.               message "Warning--$realmsg"
  131.               return
  132.           }
  133.       }
  134.       default {
  135.           bib_GotoError $msg [file dirname $base_aux]
  136.       }
  137.     } 
  138. }
  139.  
  140. ## 
  141.  # -------------------------------------------------------------------------
  142.  #   
  143.  # "bib_OpenFile" --
  144.  #  
  145.  #  Given a filename, and the directory of the base '.aux' file, try and
  146.  #  find the file.  If we don't succeed, pass the request onto the TeX
  147.  #  code.
  148.  # -------------------------------------------------------------------------
  149.  ##
  150. proc bib_OpenFile {filename {dir ""}} {
  151.     # look where base file was
  152.     if {![catch {openFileQuietly "${dir}:${filename}"}]} {
  153.         return
  154.     }
  155.     # look in bibtex inputs folder
  156.     global bibtexSig
  157.     if {![catch {openFileQuietly "[file dirname [nameFromAppl $bibtexSig]]:BibTeX inputs:${filename}"}]} {
  158.         return
  159.     } 
  160.     # look in all usual tex places
  161.     openTeXFile "$filename"
  162.     return
  163. }
  164.  
  165. ## 
  166.  # -------------------------------------------------------------------------
  167.  #   
  168.  # "bib_NoEntryExists" --
  169.  #  
  170.  #  No entry exists in the known .bib files.  Either add an entry, possibly
  171.  #  in a new bibliography file, or add a .bib file to those currently
  172.  #  searched.
  173.  # -------------------------------------------------------------------------
  174.  ##
  175. proc bib_NoEntryExists {item {basefile ""}} {
  176.     set choice [prompt  \
  177.         "No entry '$item' exists.  What do you want to do?" \
  178.         "New entry" "Choices" \
  179.         "New entry" "New entry in new bibliography file" \
  180.         "Add .bib file to \\bibliography\{…\}" ]
  181.     switch $choice {
  182.       "New entry" {
  183.           # need to pick a .bib file
  184.           set bibfile [bibPickBibliography 1 \
  185.               "Select a bibliography file to which to add an entry"]
  186.           openTeXFile $bibfile
  187.           global entryNames
  188.           bibFormatSetup
  189.           newEntry [listpick -p "Which type of entry?" $entryNames]
  190.           insertText $item
  191.           nextTabStop
  192.       }
  193.       "New entry in new bibliography file" {
  194.         set bibfile [putfile "Save new bibliography as…" ".bib"]
  195.         if {$bibfile == ""} {
  196.             error "No bibliography file selected."
  197.         } else {
  198.             new -n $bibfile
  199.         }        
  200.           global entryNames
  201.           bibFormatSetup
  202.           newEntry [listpick -p "Which type of entry?" $entryNames]
  203.           insertText $item
  204.           nextTabStop
  205.       }
  206.       "Add .bib file to \\bibliography\{…\}" {
  207.           if {$basefile == ""} {set basefile [TeX_currentBaseFile]}
  208.           # find .aux and open base .tex/.ltx
  209.           set base [lindex [split $basefile "."] 0]
  210.           if [file exists ${base}.tex] {
  211.               set base ${base}.tex
  212.           } elseif [file exists ${base}.ltx] {
  213.               set base ${base}.ltx
  214.           } else {
  215.               error "Base file with name '${base}.xxx' not found." 
  216.           }                                   
  217.           openFileQuietly ${base}
  218.           
  219.           # find bibliography, position cursor and add
  220.           endOfBuffer
  221.           if [catch {set pos [search -f 0 -r 0 -m 0 "\\bibliography\{" [getPos]]}] {
  222.               # add the environment
  223.               set pos [search -f 0 "\\end\{document\}" [getPos]]
  224.               goto [lindex $pos 0]
  225.               set preinsert "\\bibliography\{"
  226.               set postinsert "\}\r\r"
  227.           } else {
  228.               set preinsert ""
  229.               set postinsert ","
  230.               goto [lindex $pos 1]
  231.           }
  232.           set bibfile [bibPickBibliography 0 \
  233.               "Select a bibliography file to add"]
  234.           insertText "${preinsert}[lindex [split $bibfile "."] 0]${postinsert}"
  235.               
  236.       }
  237.       "Cancel" {
  238.           # nothing
  239.       }
  240.       }               
  241. }
  242.  
  243. ## 
  244.  # -------------------------------------------------------------------------
  245.  #     
  246.  # "bib_GotoError" --
  247.  #    
  248.  #    Parse and goto a specific error    in a particular    file.  Look    locally    for
  249.  #    the    correct    text in    case we've edited the file.
  250.  # -------------------------------------------------------------------------
  251.  ##
  252. proc bib_GotoError {msg {dir ""}} {
  253.     # is it an 'I found no xxxx while reading file yyy' error?
  254.     if [regsub {I found no .*---while reading file (.*)} $msg {\1} filename] {
  255.         bib_OpenFile $filename $dir
  256.         beep
  257.         message $msg
  258.         return
  259.     }
  260.     
  261.       # It's a more specific error.  
  262.     # Extract type, line, filename, and position of error
  263.       set errtype [lindex [split $msg "-"] 0]
  264.       if ![regsub {.*line ([0-9]+) .*} $msg {\1} line] {
  265.           error "Failed to parse line number from BibTeX error"
  266.       }
  267.     if ![regsub    {.*of file (.*) a .*} $msg {\1}    filename] {
  268.         error "Failed to parse filename    from BibTeX    error"
  269.     }
  270.     if ![regsub    {.*a '(.*)' at.*} $msg {\1}    problem] {
  271.         error "Failed to parse problem text    from BibTeX    error"
  272.     }
  273.     if ![regsub    {.*at (.*)}    $msg {\1} linepos] {
  274.         error "Failed to parse line    position from BibTeX error"
  275.     }
  276.       bib_OpenFile $filename $dir
  277.       goto [rowColToPos $line $linepos]
  278.     # Un-map the encoding we did on the other end.
  279.     regsub "‘" $problem "\{" problem
  280.     regsub "’" $problem "\}" problem
  281.     # Un-map the encoding we did on the other end.
  282.     regsub "‘" $errtype "\{" errtype
  283.     regsub "’" $errtype "\}" errtype
  284.     set pos [getPos]
  285.     if {[getText [lineStart $pos] $pos] != $problem} {
  286.         # we've    edited the file; look locally
  287.         set pr "^[quoteExpr2 $problem]"
  288.         if {![catch {search -f 0 -r 1 -l [expr $pos - 300] $pr $pos} found]} {
  289.             set pos [lindex $found 1]
  290.         } elseif {![catch {search -f 1 -r 1 -l [expr $pos + 300] $pr $pos} found]} {
  291.             set pos [lindex $found 1]
  292.         }            
  293.     }
  294.       select [lineStart $pos] $pos
  295.       beep
  296.       message "$errtype"
  297.       return
  298. }
  299.  
  300. ## 
  301.  # -------------------------------------------------------------------------
  302.  #     
  303.  # "TeXEnsureSearchPathSet"    --
  304.  #    
  305.  #    Make sure TeX mode has built our search    path, so we    can    find 
  306.  #    bibliography files.     Perhaps we    should have    our    own    variable
  307.  #    for    these?
  308.  # -------------------------------------------------------------------------
  309.  ##
  310. proc TeXEnsureSearchPathSet {} {
  311.     global TeXSearchPath
  312.     if { [llength $TeXSearchPath] == 0 } {
  313.         message "building TeX search path…"
  314.         set TeXSearchPath [buildTeXSearchPath]
  315.         message ""
  316.     }
  317. }
  318.  
  319. ## 
  320.  # -------------------------------------------------------------------------
  321.  #     
  322.  # "bibPickBibliography" --
  323.  #    
  324.  #    Put    up a list-dialog so    the    user can select    a bibliography file    for
  325.  #    some action    (taken by the caller).    Can    also create    a new file if
  326.  #    desired.
  327.  # -------------------------------------------------------------------------
  328.  ##
  329. proc bibPickBibliography {{allowNew 1} {prompt "Pick a bibliography file"}} {
  330.     set biblist [bibListAllBibliographies]
  331.     if $allowNew {
  332.         lappend biblist {New file…}
  333.     }
  334.     global Bib_defaultBib
  335.     set bibfile [listpick -p $prompt -L $Bib_defaultBib $biblist]
  336.     if {$bibfile == ""} {
  337.         error "No bibliography file selected."
  338.     } elseif {$bibfile == "New file…" } {
  339.         set bibfile [putfile "Save new bibliography as…" ".bib"]
  340.         if {$bibfile == ""} {
  341.             error "No bibliography file selected."
  342.         } else {
  343.             set fout [open $bibfile w]
  344.             close $fout
  345.         }        
  346.     }
  347.     return [file tail [set Bib_defaultBib $bibfile]]
  348. }
  349.  
  350. ## 
  351.  # -------------------------------------------------------------------------
  352.  #     
  353.  # "bibListAllBibliographies" --
  354.  #    
  355.  #    Return all bibliographies on the search    path.  Optionally only return
  356.  #  those which are in a given .aux file.
  357.  # -------------------------------------------------------------------------
  358.  ##
  359. proc bibListAllBibliographies { {auxfile ""} } {
  360.     TeXEnsureSearchPathSet
  361.     global TeXSearchPath
  362.     set biblist {}
  363.     if {$auxfile == "" || [catch {set fid [open "$auxfile" r]}]} {
  364.         foreach d $TeXSearchPath {
  365.             eval lappend biblist [glob -nocomplain ${d}*.bib]
  366.         }
  367.     } else {
  368.         set bibs {}
  369.         # get list of bibs from .aux file
  370.         set cid [scancontext create]
  371.         scanmatch $cid {bibdata\{([^\}]*)\}} {
  372.             eval lappend bibs [split $matchInfo(submatch0) ","]
  373.         }
  374.         scanfile $cid $fid
  375.         close $fid
  376.         scancontext delete $cid
  377.         # find the full paths
  378.         foreach b $bibs {
  379.             foreach d $TeXSearchPath {
  380.                 if [file exists ${d}${b}.bib] {
  381.                     lappend biblist ${d}${b}.bib
  382.                     break
  383.                 }
  384.             }        
  385.         }
  386.     }
  387.     
  388.     return $biblist
  389. }
  390.  
  391. ## 
  392.  # -------------------------------------------------------------------------
  393.  #     
  394.  # "bibGotoEntry" --
  395.  #    
  396.  #    Look for a bib entry in    the    given list of files, or    if that    fails or
  397.  #    isn't given, look in all available bib files on    the    search path.
  398.  # -------------------------------------------------------------------------
  399.  ##
  400. proc bibGotoEntry {entry {biblist {}}} {
  401.     if ![catch {bib_GotoEntryFromIndex $entry}] {
  402.         return
  403.     }
  404.     if {[llength $biblist] && ![catch {bib_GotoEntry $entry $biblist}]} {
  405.         return
  406.     }
  407.     if ![catch {bib_GotoEntry $entry [bibListAllBibliographies]}] {
  408.         return
  409.     }
  410.     beep
  411.     error "Can't find entry '$entry' in the .bib file(s)"
  412. }
  413.  
  414. ## 
  415.  # -------------------------------------------------------------------------
  416.  #     
  417.  # "bib_GotoEntryFromIndex"    --
  418.  #    
  419.  #    Look in    the    bibIndex and find an entry very    quickly.
  420.  # -------------------------------------------------------------------------
  421.  ##
  422. proc bib_GotoEntryFromIndex {entry} {
  423.      set bibTopPat {@([a-zA-Z]+)[\{\(][     ]*}
  424.     global PREFS
  425.     # if it fails, but we succeed later, we will have the opportunity
  426.     # to rebuild the bibIndex
  427.     if [file exists "${PREFS}:bibIndex"] {
  428.         source "${PREFS}:bibIndex"
  429.         global bibIndex
  430.         foreach f [array names bibIndex] {
  431.             if [regexp "\[ \r\n\]$entry\[ \r\n\]" "$bibIndex($f)"] {
  432.                 openFileQuietly $f
  433.                 set p [search -f 1 -r 1 $bibTopPat$entry 0]
  434.                 eval select $p
  435.                 centerRedraw
  436.                 eval select $p
  437.                 unset bibIndex
  438.                 return
  439.             }
  440.         }
  441.         unset bibIndex
  442.     }
  443.     error "Entry '$entry' not found in bibIndex"
  444. }
  445.  
  446. ## 
  447.  # -------------------------------------------------------------------------
  448.  #     
  449.  # "bib_FindAllEntries"    --
  450.  #    
  451.  #    Find all entries with a    given prefix, optionally attaching the titles
  452.  #    of the entries (this requires a    bibDatabase    file to    be setup).    Used
  453.  #    by TeX citation    completions: \cite{Darley<cmd-Tab>
  454.  # -------------------------------------------------------------------------
  455.  ##
  456. proc bib_FindAllEntries {eprefix {withtitles 1}} {
  457.     global PREFS 
  458.     set matches {}
  459.     if $withtitles {
  460.         if ![file exists "${PREFS}:bibDatabase"] {
  461.             if {[askyesno "No bibDatabase exists, shall I make one?"]=="yes"} {
  462.                 bibMakeDatabase
  463.             } else {
  464.                 error "No bib database exists"
  465.             }
  466.         }
  467.         set cid [scancontext create]
  468.         scanmatch $cid "^${eprefix}" {
  469.             lappend matches [list $matchInfo(line)]
  470.         }
  471.         set fid [open "${PREFS}:bibDatabase" r]
  472.         scanfile $cid $fid
  473.         close $fid
  474.         scancontext delete $cid    
  475.     } else {
  476.         global bibIndex
  477.         source "${PREFS}:bibIndex"
  478.         foreach f [array names bibIndex] {
  479.             if { [set matched [modeListCompletions $eprefix "bibIndex(${f})"]] != 0 } {
  480.                 eval lappend matches $matched
  481.             }
  482.         }
  483.         unset bibIndex
  484.     }
  485.     return $matches    
  486. }
  487.  
  488. ## 
  489.  # -------------------------------------------------------------------------
  490.  #     
  491.  # "bib_GotoEntry" --
  492.  #    
  493.  #    Find a bib entry in    one    of the given list of files,    and    signal an
  494.  #    error if the entry isn't found.     I think this is the quickest way.
  495.  # -------------------------------------------------------------------------
  496.  ##
  497. proc bib_GotoEntry {entry biblist} {
  498.      set bibTopPat {@([a-zA-Z]+)[\{\(][     ]*}
  499.      set cid [scancontext create]
  500.      scanmatch $cid $bibTopPat$entry {
  501.          set found "$matchInfo(offset)"
  502.      }
  503.      set found ""
  504.     foreach f $biblist {
  505.         message "Searching [file tail $f]…"
  506.         if {![catch {set fid [open $f]}]} {
  507.             scanfile $cid $fid
  508.             close $fid
  509.             if {$found != ""} {
  510.                 openFileQuietly $f
  511.                 goto $found
  512.                 centerRedraw
  513.                 select $found [nextLineStart $found]
  514.                 scancontext delete $cid
  515.                 global Bib_AutoIndex
  516.                 # make the index since it was obviously out of date                
  517.                 if {$Bib_AutoIndex == 2 || [askyesno "The bibIndex is obviously out of date.  Rebuild?"]=="yes"} {
  518.                     bibMakeIndex
  519.                 }
  520.                 return
  521.             }    
  522.         }
  523.     }
  524.     scancontext delete $cid
  525.     error "Entry '$entry' not found."
  526. }
  527.  
  528.  
  529. ## 
  530.  # -------------------------------------------------------------------------
  531.  #     
  532.  # "bibMakeIndex" --
  533.  #    
  534.  #    Build the bibIndex file    which allows for very fast lookup of bib
  535.  #    entries.
  536.  # -------------------------------------------------------------------------
  537.  ##
  538. proc bibMakeIndex {} {
  539.     global PREFS 
  540.     set bibTopPat2 {^[     ]*@([a-zA-Z]+)[\{\(][     ]*([^=,     ]+)}    
  541.      set cid [scancontext create]
  542.      # this will actually mark strings as well
  543.      scanmatch $cid $bibTopPat2 {
  544.          if {[string tolower $matchInfo(submatch0)] != "string"} {
  545.              lappend found $matchInfo(submatch1)
  546.          }
  547.      }
  548.      set bdatout [open "${PREFS}:bibDatabase" w]
  549.      set bout [open "${PREFS}:bibIndex" w]
  550.      puts $bout "# Bibliography index file for quick reference lookup"
  551.      puts $bout "# Created on [mtime [now]]"
  552.      puts $bdatout "# Bibliography database file for quick reference lookup"
  553.      puts $bdatout "# Created on [mtime [now]]"
  554.     foreach f [bibListAllBibliographies] {
  555.         set found {}
  556.         puts $bout "set \"bibIndex($f)\" \{"
  557.         message "Scanning [file tail $f]…"
  558.         if {![catch {set fid [open $f]}]} {
  559.             scanfile $cid $fid
  560.             close $fid
  561.         }
  562.         # we sort so we can search it efficiently for all entries with
  563.         # a given prefix.
  564.         puts $bout " [lsort $found] "
  565.         puts $bout "\}"
  566.     }
  567.     close $bout
  568.     scancontext delete $cid
  569.     message "bibIndex creation complete"
  570. }
  571.  
  572. ## 
  573.  # -------------------------------------------------------------------------
  574.  #     
  575.  # "bibMakeDatabase" --
  576.  #    
  577.  #    Build the bibDatabase which    allows speedy completion of    citations and
  578.  #    contains titles, so    that you can pick the correct completion easily.
  579.  # -------------------------------------------------------------------------
  580.  ##
  581. proc bibMakeDatabase {} {
  582.      set bibTopPat {@([a-zA-Z]+)[\{\(][     ]*}
  583.     global PREFS
  584.     set bdatout [open "${PREFS}:bibDatabase" w]
  585.     # if it fails, but we succeed later, we will have the opportunity
  586.     # to rebuild the bibIndex
  587.     foreach f [bibListAllBibliographies] {
  588.         message "Scanning ${f}…"
  589.         openFileQuietly $f
  590.         set p 0
  591.         while {![catch {search -f 1 -r 1 $bibTopPat $p} epos]} {
  592.             set p [lindex $epos 1]
  593.             set np [nextLineStart $p]
  594.             set entry [string trim [getText $p $np] "\{\( \t\r,"]
  595.             if ![catch {search -f 1 -r 1 {title[ \t]*=.*,[ \t]*\r} $np} epos] {
  596.                 set title [eval getText $epos]
  597.                 regsub -all "\[\r\t\]+" $title { } title
  598.                 set title [string range $title [string first "=" $title] end]
  599.                 set title [string trim $title " =\{\}\","]
  600.                 puts $bdatout "$entry \{$title\}"
  601.                 set p [lindex $epos 1]
  602.             }
  603.         }   
  604.         killWindow
  605.     }
  606.     close $bdatout
  607. }
  608.